﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using System.Xml.Serialization;
using System.IO;

namespace StopWatch
{
    public partial class TimerForm : Form
    {
        private delegate void UpdateLabelDelegate(string item, bool timeOver);
        Thread _timerThread;
        bool _bContinue;
        bool _closedByContextMenu;
        StopWatchSettings _settings;

        private const int WM_NCLBUTTONDOWN = 0xA1;
        private const int HT_CAPTION = 0x2;

        [DllImportAttribute("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd,
                         int Msg, int wParam, int lParam);
        [DllImportAttribute("user32.dll")]
        public static extern bool ReleaseCapture();

        public TimerForm()
        {
            _bContinue = false;
            _closedByContextMenu = false;
            InitializeComponent();
        }

        private string SettingsPath
        {
            get
            {
                return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StopWatchSettings.xml");
            }
        }

        private void StartTimer()
        {
            _timerThread = new Thread(TimerThreadProc);
            _bContinue = true;
            _timerThread.Start();
        }
        private void TimerThreadProc()
        {
            AutoResetEvent waitEvent = new AutoResetEvent(false);
            TimeSpan tickElapsed = TimeSpan.Zero;
            TimeSpan tickRemaining = TimeSpan.Zero;
            
            while (_bContinue)
            {
                waitEvent.WaitOne(1000);
                bool timeOver = false;
                tickElapsed = tickElapsed.Add(new TimeSpan(0, 0, 1));
                tickRemaining = _settings.EndTime - DateTime.Now;
                string strLabel=string.Empty;
                if (tickRemaining <= TimeSpan.Zero)
                {
                    timeOver = true;
                }
                if (_settings.ShowElapsedTime)
                {
                    strLabel = string.Format("{0}:{1}:{2}", Math.Abs(tickElapsed.Hours), Math.Abs(tickElapsed.Minutes), Math.Abs(tickElapsed.Seconds));
                }
                else
                {
                    strLabel = string.Format("+ {0}:{1}:{2}", Math.Abs(tickRemaining.Hours), Math.Abs(tickRemaining.Minutes), Math.Abs(tickRemaining.Seconds));
                }

                 

                UpdateLabel(strLabel, timeOver);
            }
        }

        private void UpdateLabel(string labelText, bool timeOver)
        {
            if (labelDisplay.InvokeRequired)
            {
                labelDisplay.Invoke(new UpdateLabelDelegate(UpdateLabel), new object[] { labelText, timeOver });
            }
            else
            {
                //labelDisplay.Text = labelText;
                Color backColor = timeOver ? Color.Red : Color.Green;
                BackColor = backColor;
                //labelDisplay.BackColor = backColor;
                Graphics g = Graphics.FromHwnd(Handle);
                Font drawFont = new Font("Arial", 28);
                SolidBrush drawBrush = new SolidBrush(Color.Black);
                StringFormat sf = new StringFormat();
                sf.LineAlignment = StringAlignment.Center;
                sf.Alignment = StringAlignment.Center;
                g.Clear(BackColor);
                g.DrawString(labelText, drawFont, drawBrush, ClientRectangle, sf);
                g = null;
                drawFont = null;
                drawBrush = null;
                sf = null;
            }
        }

        private void SetAsTopMost(bool topMost = true)
        {
            TopMost = topMost;
            FormBorderStyle = FormBorderStyle.None;
            WindowState = FormWindowState.Normal;
        }

        private void TimerForm_Load(object sender, EventArgs e)
        {
            UpdateLabel("Iniializing", false);
            LoadSettings();
            SetPosition();
            StartTimer();
            SetRunOnStartUpMenuItemCheck();
            BringToFrontToolStripMenuItemChecked();
        }

        private void LoadSettings()
        {
            try
            {
                _settings = new StopWatchSettings();
                XmlSerializer serializer = new XmlSerializer(typeof(StopWatchSettings));
                StreamReader reader = new StreamReader(SettingsPath);
                object deserialized = serializer.Deserialize(reader.BaseStream);
                _settings = (StopWatchSettings)deserialized;
            }
            catch (Exception)
            {

            }
            finally
            {

            }
        }

        private void SaveSettings()
        {
            try
            {
                XmlSerializer serializer = new XmlSerializer(typeof(StopWatchSettings));
                StreamWriter writer = new StreamWriter(SettingsPath);
                serializer.Serialize(writer.BaseStream, _settings);
            }
            catch (Exception)
            {
            }
        }

        private void BringToFrontToolStripMenuItemChecked()
        {
            //read the configurations and set the value.
            bool topMost = _settings.TopMost;
            bringToFrontToolStripMenuItem.Checked = topMost;
            SetAsTopMost(topMost);
        }

        private void SetRunOnStartUpMenuItemCheck()
        {
            RegistryKey add = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
            runOnStartupToolStripMenuItem.Checked = (null != add.GetValue("StopWatch"));
        }

        private void SetPosition()
        {
            var desktopWorkingArea = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea;
            Left = desktopWorkingArea.Right - Width;
            Top = desktopWorkingArea.Bottom - Height;
        }

        private void TimerForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = !_closedByContextMenu;
        }

        private void pauseToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (pauseToolStripMenuItem.Text == "Pause")
            {
                pauseToolStripMenuItem.Text = "Resume";
                _timerThread.Suspend();
            }
            else
            {
                pauseToolStripMenuItem.Text = "Pause";
                _timerThread.Resume();
            }
        }

        private void stopToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (stopToolStripMenuItem.Text == "Stop")
            {
                try
                {
                    _timerThread.Abort();
                }
                catch (Exception)
                {
                }
                stopToolStripMenuItem.Text = "Start";
            }
            else
            {
                stopToolStripMenuItem.Text = "Stop";
                StartTimer();
            }

        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                _timerThread.Abort();
            }
            catch (Exception)
            {
            }
            _closedByContextMenu = true;
            Close();
        }

        private void runOnStartupToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RegistryKey add = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
            if (runOnStartupToolStripMenuItem.Checked)
            {
                add.SetValue("StopWatch", "\"" + Application.ExecutablePath.ToString() + "\"");
            }
            else
            {
                add.DeleteValue("StopWatch");
            }
        }

        private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SettingsForm settings = new SettingsForm(_settings);
            if (DialogResult.OK == settings.ShowDialog())
            {
                SaveSettings();
            }
        }

        private void TimerForm_MouseDown(object sender, MouseEventArgs e)
        {
            MoveWindow(e);
        }

        private void MoveWindow(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                ReleaseCapture();
                SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
            }
        }

        private void labelDisplay_MouseDown(object sender, MouseEventArgs e)
        {
            MoveWindow(e);
        }

        private void bringToFrontToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _settings.TopMost = bringToFrontToolStripMenuItem.Checked;
            SetAsTopMost(bringToFrontToolStripMenuItem.Checked);
            SaveSettings();
        }
    }
}
